package com.xunk.scene.handler.delay;


import javax.validation.constraints.NotNull;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @ProjectName: HIM
 * @Package: com.xunk.scene.handler.delay
 * @ClassName: DelayTask
 * @Author: luanzhiwei
 * @Description: 延时任务
 * @Date: 2021/5/18 14:37
 * @Version: 1.0
 */
public class DelayTask<T extends Runnable> implements Delayed {

    /**
     * 延时时间
     */
    private final long time;
    /**
     * 任务对象
     */
    private final T task;


    public static final AtomicLong ATOMIC_LONG = new AtomicLong(0);

    private final long n;

    /**
     * 有参构造
     *
     * @param timeout
     * @param t
     */
    public DelayTask(long timeout, T t) {
        this.time = System.currentTimeMillis() + timeout;
        this.task = t;
        this.n = ATOMIC_LONG.getAndIncrement();
    }

    /**
     * Returns the remaining delay associated with this object, in the
     * given time unit.
     *
     * @param unit the time unit
     * @return 获取延迟时间余额，如果返回负数或0，表示已经达到延时时间
     */
    @Override
    public long getDelay(@NotNull TimeUnit unit) {
        return unit.convert(this.time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * @param o the object to be compared.
     * @return 小于指定对象，返回一个负整数。等于指定对象，返回0，大于指定对象返回一个正整数
     * @throws NullPointerException if the specified object is null
     * @throws ClassCastException   if the specified object's type prevents it
     *                              from being compared to this object.
     */
    @Override
    public int compareTo(@NotNull Delayed o) {
        // TODO Auto-generated method stub
        if (o == this) // compare zero ONLY if same object
        {
            return 0;
        }
        if (o instanceof DelayTask) {
            DelayTask x = (DelayTask) o;
            long diff = time - x.time;
            if (diff < 0) {
                return -1;
            } else if (diff > 0) {
                return 1;
            } else if (n < x.n) {
                return -1;
            } else {
                return 1;
            }
        }
        long d = (getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        return (d == 0) ? 0 : ((d < 0) ? -1 : 1);
    }

    /**
     * 获取当前对象
     *
     * @return
     */
    public T getTask() {
        return this.task;
    }

    /**
     * hashcode
     *
     * @return
     */
    @Override
    public int hashCode() {
        return task.hashCode();
    }

    /**
     * 比较
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof DelayTask) {
            return obj.hashCode() == hashCode() ? true : false;
        }
        return false;
    }
}
